perm filename CL2[COM,LSP] blob sn#813020 filedate 1986-03-19 generic text, type T, neo UTF8
Part 2 of 2
				Error Proposal #5 by KMP 3/15/86, Page 13

PROCEED-CASE-NAME proceed-case				[Function]

  Returns the name of the given PROCEED-CASE, or NIL if it is not named.

FIND-PROCEED-CASE name condition			[Function]

  Searches for a proceed case by the given NAME which is applicable to the
  given condition in the current dynamic contour.

  If NAME is a proceed function name, then the innermost (ie, most recently
  established) proceed case with that function name that matches the given
  condition is returned. NIL is returned if no such proceed case is found.

  If NAME is a proceed case object, then it is simply returned unless it
  is not currently valid for use. In that case, NIL is returned.

INVOKE-PROCEED-CASE proceed-case condition &rest values	
							[Function]

  Transfers control to the given PROCEED-CASE, passing the given VALUES.
  The PROCEED-CASE must a proceed case or the name of a proceed function
  which is valid in the current dynamic context. If the argument is not
  valid, an error will be signalled.

  This operation is used primarily as a sub-primitive for implementing
  named proceed functions, but may be necessary when writing certain kinds
  of portable, interactive debuggers. 
  See Footnote: {INVOKE-PROCEED-CASE vs Named Proceed Functions}

				Error Proposal #5 by KMP 3/15/86, Page 14

DEFINE-PROCEED-FUNCTION name [keyword value]* &rest variables
							[Special Form]

  Valid KEYWORD/VALUE pairs are the same as those which are defined for
  the PROCEED-CASE special form. That is, :TEST, :CONDITION, 
  :REPORT-FUNCTION, and :REPORT.

  This form defines a function called NAME which will proceed an error in 
  a typed way. The proceed function takes a required argument of a condition
  and optional arguments which are given by the VARIABLES specification.

  The variable CONDITION is bound to the condition object itself so that it
  will be accessible during the initialization of the optional arguments.

  Each element of VARIABLES has the form 
       VARIABLE-NAME
    or (VARIABLE-NAME INITIAL-VALUE).
  If initial-value is not supplied, it defaults to NIL.

  For example, here are some possible proceed functions which might be useful
  in conjunction with the BAD-FOOD-COLOR error we used as an example earlier:

	(DEFINE-PROCEED-FUNCTION USE-FOOD 
	    :REPORT "Use another food."
	  (FOOD (READ-TYPED-OBJECT 'FOOD "Food to use instead: ")))

	(DEFINE-PROCEED-FUNCTION USE-COLOR 
	    :REPORT "Change the food's color."
	  (COLOR (READ-TYPED-OBJECT 'FOOD "Color to make the food: ")))

        (DEFUN MAYBE-USE-WATER (CONDITION) ;A sample named handler
	  (IF (EQ (BAD-FOOD-COLOR-FOOD CONDITION) 'MILK)
	      (USE-FOOD CONDITION 'WATER)))

	(CONDITION-BIND ((BAD-FOOD-COLOR #'MAYBE-USE-WATER))
	  ...)

  The condition argument to a proceed function is optional. If not provided,
  it defaults to NIL. This may be useful in the implementation of proceed 
  functions such as ABORT, which are not normally called with a condition argument.

  If a named proceed function is invoked in a context in which there is 
  no active proceed case by that name, the proceed function simply returns NIL.
  So, for example, in each of the following pairs of handlers, the first is
  equivalent to the second except for efficiency:
  and less efficient:

	#'(LAMBDA (CONDITION)					;OK, but slow
	    (IF (FIND-PROCEED-CASE 'USE-FOOD CONDITION)
		(USE-FOOD CONDITION 'MILK)))

	#'(LAMBDA (CONDITION) (USE-FOOD CONDITION 'MILK))	;Preferred

     -----

	#'(LAMBDA (CONDITION)
	    (USE-FOOD  CONDITION 'CHOCOLATE)
	    (USE-COLOR CONDITION 'ORANGE))

	#'(LAMBDA (CONDITION)
	    (COND ((FIND-PROCEED-CASE 'USE-FOOD CONDITION)
		   (USE-FOOD CONDITION 'CHOCOLATE))
		  ((FIND-PROCEED-CASE 'USE-COLOR CONDITION)
		   (USE-COLOR CONDITION 'ORANGE))))

				Error Proposal #5 by KMP 3/15/86, Page 15

*** NOTE: In contrast to the way that Zetalisp has defined ABORT as a kind
***       of condition to be handled, we define ABORT as a manner of proceeding
***       a condition rather than as a condition type to be handled.

CATCH-ABORT print-form &body forms			[Macro]

  Sets up a PROCEED-CASE context for the proceed function ABORT.

  If no ABORT is done while executing FORMS, all values returned by the last 
  form in FORMS are returned. If an ABORT transfers control to this CATCH-ABORT, 
  two values are returned: NIL and the condition which was given to ABORT 
  (or NIL if none was given).

  CATCH-ABORT could be defined by:

	(DEFMACRO CATCH-ABORT (PRINT-FORM &REST FORMS)
	  `(PROCEED-CASE (PROGN ,@FORMS)
	     (ABORT (CONDITION)
                 :REPORT ,PRINT-FORM
	         :TEST (LAMBDA (IGNORE) T)
	       (VALUES NIL CONDITION))))

  Example:

    (DEFUN READ-EVAL-PRINT-LOOP (LEVEL)
      (CATCH-ABORT (FORMAT T "Exit command level ~D." LEVEL)
        (LOOP
	  (CATCH-ABORT (FORMAT T "Return to command level ~D." LEVEL)
            (PRINT (EVAL (READ)))))))

  If while executing (READ-EVAL-PRINT-LOOP 1) the user typed (+ 'a 3)
  and landed in the debugger, he might expect to see something like:

	The argument, A, to the function + was of the wrong type.
	The function expected a number.
	[0] Lisp Toplevel
	[1] Exit command level 1
	[2] Return to command level 1
	[3] Supply a new value for this argument
	Selection: 
		
ABORT &optional condition				[Function]

  Transfers control to the innermost (dynamic) CATCH-ABORT form, causing it to
  return NIL immediately. 

  It is not usually useful to specify a CONDITION. This is because the default
  test for ABORT unconditionally returns true and all CATCH-ABORT forms are
  therefore likely to be visible. The only such forms which might not be visible
  are those which override the default test. In that rare case, specifying
  a CONDITION may make a difference.

  ABORT could be defined by:

	(DEFINE-PROCEED-FUNCTION ABORT
	    :REPORT "Abort."
	    :TEST (LAMBDA (IGNORE) T))

  
				Error Proposal #5 by KMP 3/15/86, Page 16

CONDITION-CASE form &rest cases				[Special Form]

  Executes the given form. Each case has the form (type ([var]) . body).
  If a condition is signalled (and not handled by an intervening handler) 
  during the execution of the form for which there is an appropriate clause
  -- ie, one for which (TYPEP condition 'type) is true -- then control is 
  transferred to the body of the relevant clause, binding the given VAR to 
  the condition which was signalled. If no error occurs, then the values
  resulting from the FORM are returned by the CONDITION-CASE.

  If VAR is not needed, it may be omitted.

  TYPE may also be a list of types, in which case it will catch conditions of
  any of the specified types.  

  Examples:

	(CONDITION-CASE (/ X Y)
	  (DIVISION-BY-ZERO () NIL))

        (CONDITION-CASE (OPEN *THE-FILE* :DIRECTION :INPUT)
 	  (FILE-ERROR (CONDITION) (FORMAT T "~&Open failed: ~A~%" CONDITION)))

	(CONDITION-CASE (SOME-USER-FUNCTION)
	  (FILE-ERROR (CONDITION) CONDITION)
	  (DIVISION-BY-ZERO () 0)
	  ((UNBOUND-VARIABLE UNDEFINED-FUNCTION) () 'UNBOUND))

IGNORE-ERRORS &body forms				[Macro]

  Executes its body in a context which handles errors of type ERROR
  by returning control to this form. If no error is signalled, any
  return values returned by the last form are returned by IGNORE-ERRORS.
  Otherwise, NIL is returned. 

  Synonym for (CONDITION-CASE (PROGN . forms) 
		(ERROR () NIL)).


Although they are not described in detail here, it is expected that the 
macros CHECK-TYPE, ASSERT, ETYPECASE, CTYPECASE, ECASE, and CCASE should 
continue to be supported essentially as described in CLtL.

				Error Proposal #5 by KMP 3/15/86, Page 17


			      PRE-DEFINED TYPES
			      -----------------

Implementation Note: The types PROCEED-CASE, CONDITION, etc. are new ``first 
  class'' types in the sense that they must be distinguishable from any other
  CL types of which they are subtypes. This is necessary because PRINC is 
  specified to treat them specially. DEFSTRUCT is one way to implement these
  types.

PROCEED-CASE						[Type]

  This is the data type used to represent a proceed case.

The CONDITION type hierarchy looks like this:

		     CONDITION
			 !
	 +---------------+---------------+
	 !               !               !
 SIMPLE-CONDITION     WARNING     SERIOUS-CONDITION
			 !               !
		  SIMPLE-WARNING         !
					 !
					 !
	     +--------------+------------+---------+
	     !              !                      !
       SIMPLE-BREAK   STORAGE-CONDITION          ERROR
			    !                      !
		   +--------+--------+             !
		   !                 !             !
	      STACK-OVERFLOW  STORAGE-EXHAUSTED    !
						   !
						   !
				       +-----------+---+------------------+--- . . .
				       !               !                  !
				 SIMPLE-ERROR    ARITHMETIC-ERROR   CONTROL-ERROR
 

The types which are non-terminals in the above tree (ie, CONDITION, 
WARNING, SERIOUS-CONDITION, STORAGE-CONDITION, ERROR, ARITHMETIC-ERROR, 
CONTROL-ERROR, etc.) are provided primarily for type inclusion 
purposes. Normally, they would not be directly instantiated. 

Implementations are permitted to support non-portable synonyms for 
these types, as well as to introduce other types which above, below, 
or between the types shown in this tree as long as the indicated 
subtype relationships are not violated. 
See Footnote: {TYPEP vs CONDITION-TYPEP}

				Error Proposal #5 by KMP 3/15/86, Page 18

CONDITION						[Type]

  All types of conditions, whether error or non-error, must inherit from 
  this type.

WARNING							[Type]

  All types of warnings should inherit from this type. 
  This is a subtype of CONDITION.

SERIOUS-CONDITION					[Type]

  Any condition, whether error or non-error, which should enter the debugger
  when signalled but not handled should inherit from this type. This is a
  subtype of CONDITION.

  Note: IGNORE-ERRORS will ignore conditions of type ERROR, not of type
  SERIOUS-CONDITION. Conditions which are serious conditions but not errors
  are typically those that may require more sophisticated handling than
  simply being ignored. For example, IGNORE-ERRORS will not ignore a
  STORAGE-CONDITION, which is a serious condition but is not generally 
  a program error.

  Compatibility Note: SERIOUS-CONDITION is similar to Zetalisp's 
  DBG:DEBUGGER-CONDITION.

ERROR							[Type]

  All types of error conditions inherit from this condition.
  This is a subtype of CONDITION.

				Error Proposal #5 by KMP 3/15/86, Page 19

The default condition type for SIGNAL is SIMPLE-CONDITION, for 
break is SIMPLE-BREAK, and for ERROR and CERROR is SIMPLE-ERROR.

SIMPLE-CONDITION					[Type]

  Conditions signalled by SIGNAL when given a format string as a first
  argument are of this type. This is a subtype of CONDITION.
  The init keywords :FORMAT-STRING and :FORMAT-ARGUMENTS are supported.

SIMPLE-WARNING						[Type]

  Conditions signalled by WARN when given a format string as a first
  argument are of this type. This is a subtype of WARNING.
  The init keywords :FORMAT-STRING and :FORMAT-ARGUMENTS are supported.

SIMPLE-BREAK						[Type]

  Conditions used by BREAK when given a format string as a first
  argument are of this type. This is a subtype of SERIOUS-CONDITION.
  The init keywords :FORMAT-STRING and :FORMAT-ARGUMENTS are supported.

  Note: This type of condition is not generally signalled, but objects
  of this type are generally used as a reference while in a break to
  compute the available proceed types. See the description of BREAK
  for more details.

SIMPLE-ERROR						[Type]

  Conditions signalled by ERROR and CERROR when given a format string 
  as a first argument are of this type. This is a subtype of ERROR.
  The init keywords :FORMAT-STRING and :FORMAT-ARGUMENTS are supported.

				Error Proposal #5 by KMP 3/15/86, Page 20

STORAGE-CONDITION					[Type]

  Conditions which relate to memory overflow conditions should inherit 
  from this type. This is a subtype of SERIOUS-CONDITION.

STACK-OVERFLOW						[Type]

  Conditions which relate to stack overflow should inherit from this type.
  This is a subtype of STORAGE-CONDITION.

STACK-EXHAUSTED						[Type]

  Conditions which relate to any kind of GC overflow should inherit from
  this type. This is a subtype of STORAGE-CONDITION.

-------------------------

CONTROL-ERROR						[Type]

  Errors in the transfer of control in a program should inherit from
  this type. This is a subtype of ERROR.

ILLEGAL-THROW						[Type]

  The error which results when THROW is given a tag which is not active
  should inherit from this. This is a subtype of CONTROL-ERROR. The
  function ILLEGAL-THROW-TAG will access the offending tag.

ILLEGAL-GO						[Type]

  The error which results when GO is given a tag which is no longer 
  available should inherit from this. This is a subtype of CONTROL-ERROR.
  The function ILLEGAL-GO-TAG will access the offending tag.

-------------------------

STREAM-ERROR						[Type]

  Errors which occur during input from or output to a stream should
  inherit from this type. This is a subtype of ERROR. The function
  STREAM-ERROR-STREAM will access the offending stream.

READ-ERROR						[Type]

  Errors which occur during an input operation on a stream should inherit
  from this type. This is a subtype of STREAM-ERROR.

END-OF-FILE						[Type]

  The error which results when a read operation is done on a stream which has no
  more tokens should inherit from this type. This is a subtype of READ-ERROR.

				Error Proposal #5 by KMP 3/15/86, Page 21

CELL-ERROR						[Type]

  Errors which occur while accessing a location should inherit from this
  type. This is a subtype of ERROR. The function CELL-ERROR-NAME will
  access the name of the offending cell.

UNBOUND-VARIABLE					[Type]

  The error which results from trying to access the value of an unbound
  variable should inherit from this type. This is a subtype of CELL-ERROR.

UNDEFINED-FUNCTION					[Type]

  The error which results from trying to access the value of an undefined
  function should inherit from this type. This is a subtype of CELL-ERROR.

-------------------------

ARITHMETIC-ERROR					[Type]

  Errors which occur while doing arithmetic type operations should inherit
  from this type. This is a subtype of ERROR. The functions
  ARITHMETIC-ERROR-OPERATION and ARITHMETIC-ERROR-OPERANDS will access the
  offending operation and arguments, respectively.

				Error Proposal #5 by KMP 3/15/86, Page 22


				FOOTNOTES
				---------

{INVOKE-PROCEED-CASE vs Named Proceed Functions}

    Some readers may wonder why there both proceed functions and an 
    INVOKE-PROCEED-CASE primitive. 
   
    The reason for named proceed functions is to formalize interfaces, 
    while the reason for PROCEED-CASE-INVOKE is to provide flexible 
    and portable access to the mechanism.
   
    INVOKE-PROCEED-CASE has the following two purposes:
     * As a sub-primitive, to implement named proceed functions.
     * To invoke anonymous proceed cases. (eg, in an interactive debugger).
   
    Writers of portable code are encouraged to prefer the use of named proceed 
    functions over the use of INVOKE-PROCEED-CASE in any situation where it is 
    feasible. Nevertheless, it should be recognized that some useful, portable 
    programs (particularly, interactive debuggers) can only be written using 
    INVOKE-PROCEED-CASE.

{TRUE}

    The function #'(LAMBDA (IGNORE) T) is going to be a common one to use in
    conjunction with this system. Hopefully we can agree that a function
    #'TRUE could be established to mean #'(LAMBDA (&REST IGNORE) T) to help
    reduce visual clutter.

{TYPEP vs CONDITION-TYPEP}

    An earlier version of this proposal used a function called CONDITION-TYPEP
    rather than using real TYPEP. Over MLY's objections, I finally chose to
    use TYPEP for the following reasons:

     * We need a type system which can deal with these issues. Reducing the
       need for TYPEP to address these issues might reduce the perceived need
       for us to converge on a better type system.

     * If we later adopt a better type system, it is possible that any
       CONDITION-TYPEP introduced now would have different inheritance rules.
       It would be undue burden on the user to have to remember the rules
       for more than one kind of type system.

     * Introducing a CONDITION-TYPEP sets up a precedent for the introduction
       of other xxx-TYPEP operations. It would be too easy for such type systems
       to vary in subtle ways. It is better to simply insist that TYPEP be 
       good enough as is, or be improved until it is good enough.

				Error Proposal #5 by KMP 3/15/86, Page 23

{:REPORT vs :REPORT-FUNCTION}

    Originally, I had :REPORT-FUNCTION, :REPORT-STRING, and :REPORT.

    Moon objected to a bunch of keywords which did similar things. He wanted
    just one keyword. He also objected to the new term "report", feeling that
    "print" was adequate. 

    I circulated a draft proposal with just a :PRINT option that did what the
    :REPORT option does in this proposal, but with no analog for the 
    :REPORT-FUNCTION. I wasn't completely happy with the absence of 
    :REPORT-FUNCTION but figured I'd live with it if it saved a lot of fuss.

    MLY objected to the absence of :PRINT-FUNCTION. So I backed up a bit
    and decided that there were probably really two camps and that we should
    just serve both. MLY also wondered why this option controlled typeout 
    only in the case where *PRINT-ESCAPE* was NIL. So I backed up and introduced
    the term "report" instead of PRINT so that people wouldn't wonder why
    the :PRINT option didn't control the entire behavior of PRIN1 and PRINT.

    The final result of this was to revert back to :REPORT and :REPORT-FUNCTION,
    but to omit :REPORT-STRING as being unnecessary. I hope that no one will
    argue a lot about this -- it will serve most people's needs and I think is
    the sort of thing we could go around and around about to no good end.

				Error Proposal #5 by KMP 3/15/86, Page 24


				  REFERENCES
				  ----------

Some background information about motivation for decisions in this proposal
may be found in my paper ``Exceptional Situations in Lisp,'' which is
available as A.I. Working Paper 268 from the MIT AI Lab publications office
(545 Technology Square, Cambridge, MA 02139).

Much of the basis of ``Exceptional Situations in Lisp'' derives from
``Signalling and Handling Conditions,'' a document published by Symbolics,
Inc.  which describes the Lisp Machine's condition system as it looked when
originally introduced in 1983.